/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package LinkerLoader;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Calendar;

/**
 * This is the main class which checks some of the error conditions of linker and loads the program.<p>
 * @author yogesh
 */
public class Loader {
    static String[][] linker_text_record = new String[1024][5];   static int linker_text_record_counter=0;
    static String[][] linker_header_record = new String[100][10]; static int linker_header_record_counter=0;
    static String[][] linker_end_record = new String[1][2];
    static Calendar calendar_instance = Calendar.getInstance();
    static String linker_debugging_value="OFF";//ON - internal , OFF - external , TEST - testing.
    static String linker_record_address = "src\\TestProgramsSP3\\link_out.txt"; static String linker_load_map_address = "src\\TestProgramsSP3\\load_map.txt";
    static String[] file_address;
    
    /**
     * This function sets the linker records. It also prints them to file.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     */
    public void buildLinkerRecord(){
        new Linker().processTextRecord(file_address,new LoadMap().load_map);
        buildEndRecord();
        try{
            File file = new File(linker_record_address);
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            for(int index=0; index<1/*linker_header_record_counter*/; index++){
                bw.write(linker_header_record[index][0]+"|"+linker_header_record[index][1]+"|"
                        +linker_header_record[index][2]+"|"+linker_header_record[index][3]+"|"
                        +linker_header_record[index][4]+"|"+linker_header_record[index][5]+"|"
                        +linker_header_record[index][6]+"|"+linker_header_record[index][7]+"|"
                        +linker_header_record[index][8]+"|"+linker_header_record[index][9]);
                bw.newLine();
            }
            for(int index=0; index<linker_text_record_counter; index++){
                bw.write(linker_text_record[index][0]+"|"+linker_text_record[index][1]+"|"
                        +linker_text_record[index][2]+"|"+linker_text_record[index][3]+"|"
                        +linker_text_record[index][4]);
                bw.newLine();
            }
            bw.write(linker_end_record[0][0]+"|"+linker_end_record[0][1]);
            bw.close();
            
            file = new File(linker_load_map_address);
            bw = new BufferedWriter(new FileWriter(file));
            for(int index=0; index<new LoadMap().load_map.length; index++){
                String[][] load_map = new LoadMap().load_map;
                    bw.write(load_map[index][0]+"|"+load_map[index][1]+"|"
                            +load_map[index][2]+"|"+load_map[index][3]);
                bw.newLine();
            }
            bw.close();
        }catch(Exception e){
            
        }
    }
    
    /**
     * This function adds one linker header record to linker header record.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     * @param module_name the name of the module.
     * @param program_length the program length.
     * @param initial_load_address initial load address of the program which contains that header record.
     */
    public void addToLinkerHeaderRecord(String module_name, String program_length, String initial_load_address){
        linker_header_record[linker_header_record_counter][0] = "LH";
        linker_header_record[linker_header_record_counter][1] = new Linker().intToFourHex(linker_header_record_counter);
        linker_header_record[linker_header_record_counter][2] = module_name;
        linker_header_record[linker_header_record_counter][3] = new Linker().intToFourHex(new Shared().getLinkerTextRecordLength(file_address));//new Linker().intToFourHex(Integer.parseInt(program_length,16));
        linker_header_record[linker_header_record_counter][4] = initial_load_address;
        linker_header_record[linker_header_record_counter][5] = String.valueOf(calendar_instance.get(Calendar.YEAR)).concat(":").concat(String.valueOf(calendar_instance.get(Calendar.DAY_OF_YEAR)));
        
        String[] hh_mm_ss_string = new String[3];
            if(calendar_instance.get(Calendar.HOUR_OF_DAY) < 10){
                hh_mm_ss_string[0] = "0".concat(String.valueOf(calendar_instance.get(Calendar.HOUR_OF_DAY)));
            } else{
                hh_mm_ss_string[0] = String.valueOf(calendar_instance.get(Calendar.HOUR_OF_DAY));
            }
            if(calendar_instance.get(Calendar.MINUTE) < 10){
                hh_mm_ss_string[1] = "0".concat(String.valueOf(calendar_instance.get(Calendar.MINUTE)));
            } else{
                hh_mm_ss_string[1] = String.valueOf(calendar_instance.get(Calendar.MINUTE));
            }
            if(calendar_instance.get(Calendar.SECOND) < 10){
                hh_mm_ss_string[2] = "0".concat(String.valueOf(calendar_instance.get(Calendar.SECOND)));
            } else{
                hh_mm_ss_string[2] = String.valueOf(calendar_instance.get(Calendar.SECOND));
            }
        linker_header_record[linker_header_record_counter][6] = hh_mm_ss_string[0].concat(":").concat(hh_mm_ss_string[1]).concat(":").concat(hh_mm_ss_string[2]);
        linker_header_record[linker_header_record_counter][7] = "ICE2-LINK";
        linker_header_record[linker_header_record_counter][8] = "1.0.0";
        linker_header_record[linker_header_record_counter][9] = "1";
        linker_header_record_counter++;
    }
    
    /**
     * 
     * @param hex_code
     * @param debug
     * @param module_name
     */
    public void addToLinkerTextRecord(String hex_code, String debug, String module_name){
        linker_text_record[linker_text_record_counter][0] = "LT";
        linker_text_record[linker_text_record_counter][1] = new Linker().intToFourHex(linker_text_record_counter);
        linker_text_record[linker_text_record_counter][2] = hex_code;
        linker_text_record[linker_text_record_counter][3] = debug;
        linker_text_record[linker_text_record_counter][4] = module_name;
        linker_text_record_counter++;
    }
    
    /**
     * This function adds the end record to linker_end_record array.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 17,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     */
    public void buildEndRecord(){
        Linker linker_instance = new Linker();
        linker_end_record[0][0] = "LE";
        linker_end_record[0][1] = linker_instance.intToFourHex(linker_text_record_counter+1/*linker_header_record_counter*/+1);
    }
    
    /**
     * This function builds the new LoadMap().LoadMap array(a member of this class).
     * Modified Log:<br>
     * May 27,2008 - Everything shifted to LoadMap.java class - Aashish Kumar.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 25,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     */
    public void buildLoadMap(){
        LoadMap loadmap_instance = new LoadMap();
        loadmap_instance.setLoadMap(file_address);
    }
    
    /**
     * This function checks if the memory space is not exceeded by the files passes as parameter to linker.
     * Also prints the error message if any.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * @return Returns 1 to proceed executing 0 to halt.
     */
    public int checkMemoryExceed(){
        //TextRecord textrecord_instance = new TextRecord();
        Shared shared_instance = new Shared();
        if(shared_instance.getLinkerTextRecordLength(file_address)<=1024){
            return 1;
        }
        
        for(int index=0; index<file_address.length;index++){
            if(file_address.length==1){
                shared_instance.throwError(192,file_address[file_address.length-1]);
                return 0;
            }
            shared_instance.throwError(193,file_address[file_address.length-1]);
            file_address = new Shared().subArray(file_address,0,file_address.length-2); 
            index=-1;
            if(shared_instance.getLinkerTextRecordLength(file_address)<=1024){
                return 1;
            }
        }
        return 0;
    }
    
    /**
     * This function sets the internal debugging mode parameters.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     */
    public void setInternalExecutionParameters(){
        linker_record_address = "D:\\out\\link_out.txt";
        file_address = new String[2];
        file_address[0] = "D:\\object files\\file1.txt";
        file_address[1] = "D:\\object files\\file2.txt";
        //file_address[2] = "D:\\object files\\file2.txt";
        linker_record_address = "D:\\out\\LinkOut.txt"; 
        linker_load_map_address = "D:\\out\\LoadMap.txt";
    }
    
    /**
     * This function sets the parameters for testing mode.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     * @param args the default args passed by user.
     */
    public int setTestingParameters(String[] args){
        if(args.length==0){
            System.out.println("Enter the Program files to link");
            return 0;
        }
        file_address = args;
        linker_record_address = "src\\TestProgramsSP3\\out_"+file_address[0].substring(file_address[0].lastIndexOf("//")+2);
        linker_load_map_address = "src\\TestProgramsSP3\\load_map.txt";
        return 1;
    }
    
    /**
     * This function sets the parameters for external execution like command prompt.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     * @param args the default args passed by user.
     */
    public int setExternalExecutionParameters(String[] args){
        if(args.length==0){
            System.out.println("Enter the Program files to link as arguments");
            return 0;
        }
        file_address = new String[args.length];
        for(int index=0; index<file_address.length; index++){
            //file_address[index] = "out\\"+args[index];
            file_address[index] = args[index];
        }
        linker_record_address = "out\\LinkOut.txt"; 
        linker_load_map_address = "out\\LoadMap.txt";
        return 1;
    }
    
    /**
     * This function clears everything and sets the program to be called again. Needed by tester.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 27,2008.<br>
     * Original Author : Yogesh Jindal.<br>
     */
    public void clearAll(){
        linker_header_record_counter=0;
        linker_text_record_counter=0;
        try{
            File file = new File(linker_record_address);
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));            
            bw.close();
            file = new File(linker_load_map_address);
            bw = new BufferedWriter(new FileWriter(file));
            bw.close();
        }catch(Exception e){
            
        }
    }
    
    /**
     * This is the main function of Loader.java. This function controls the working of linker/loader.<p>
     * Modified Log: None.<br>
     * Error Condition tested: None.<br>
     * Creation Date : May 25,2008.<br>
     * Original Author: Yogesh Jindal.<br>
     * 
     * @param args - the command line arguments passed to the linker.
     */
    public static void main(String[] args){
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Loader loader_instance = new Loader();
        if(loader_instance.linker_debugging_value.contentEquals("ON")){
            loader_instance.setInternalExecutionParameters();
        }else if(loader_instance.linker_debugging_value.contentEquals("OFF")){
            if(loader_instance.setExternalExecutionParameters(args)==0){
                return;
            }
        }else if(loader_instance.linker_debugging_value.contentEquals("TEST")){
            if(loader_instance.setTestingParameters(args)==0){
                return;
            }
        }else{
            return;
        }
        loader_instance.clearAll();        
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        
        if(loader_instance.checkMemoryExceed()==1){
            loader_instance.buildLoadMap();
            loader_instance.buildLinkerRecord();
        }
    }
}
